#ifndef AUDIO_H
#define AUDIO_H

#include <SDL/SDL.h>
#include <vector>
#include <iostream>

#define FREQUENCE 44100     // Fr�quence de restitution par d�faut
#define	FORMAT    AUDIO_S16 // Format des �chantillons par d�faut
#define NBCANAUX  2         // Nombre de canaux par d�faut
#define AUDIOBUFF 2048      // Taille du buffer audio par d�faut

using namespace std;

class Lecteur;     // Classe responsable de la restitution
class Source;      // Source d'�chantillons
class Lecture;     // It�rateur de source (lecture simple)

class LectureRVVB; // Lecture avec r�p�tition / volume / vitesse / balance

// *************************************** LECTEUR

class Lecteur {
  friend ostream & operator << (ostream &, const Lecteur &);

 public:

  /* Type �num�r� indiquant le statut du lecteur */
  enum Statut {Erreur, Stop, Play, Pause};

  /* Constructeur :
     -> ouvre le p�riph�rique audio
     -> enregistre les caract�ristiques de restitution */
  Lecteur(int    _frequence          = FREQUENCE ,
	  Uint16 _format             = FORMAT    ,
	  Uint8  _nbcanaux           = NBCANAUX  ,
	  Uint16 _taille_audiobuffer = AUDIOBUFF );
  
  /* Destructeur : fermeture du p�ripherique audio */
  virtual ~Lecteur();

  /* Activation du thread audio (la restitution d�marre) */
  virtual void lecture();

  /* Suspension du thread audio (la restitution est interrompue) */
  virtual void pause();

  /* Fonction callback appelee par le thread audio :
     correspond au prototype du champ "callback" de SDL_AudioSpec */
  static void callback_audio(void *udata, Uint8 *stream, int len);

  SDL_mutex * mutex;  // Verrou pour les donn�es lues par le thread audio
  Statut statut;      // Etat du lecteur
  int    frequence;   // fr�quence de restitution
  Uint16 format;      // format des �chantillons
  Uint8  nbcanaux;    // nombre de canaux en sortie
  int    taille_bloc; // taille des blocs d'�chantillons (calcul�)
  Uint8  silence;     // valeur du silence (calcul�)

  vector<Source *> sources; // listes des sources associ�es
};

// *************************************** SOURCE

class Source {
  friend ostream & operator << (ostream &, const Source &);
  
 public:

  /* Constructeur :
     -> charge le fichier
     -> converti les �chantillons
     -> enregistre la source dans le lecteur */
  Source(Lecteur * _lecteur, char * _fichier);
  
  /* Destructeur :
     -> lib�ration du buffer
     -> d�sinscription de la source dans le lecteur
     -> lib�ration des lectures */
  virtual ~Source();

  /* Mixage dans le buffer audio (appel� par le callback audio) */
  virtual void mix_audio(Uint8 *stream, int len);

  bool         erreur;  // probl�me de construction de la source
  Lecteur *    lecteur; // lecteur charg� de la diffusion
  const char * fichier; // nom du fichier wav
  Uint8 *      buffer;  // buffer des �chantillons convertis
  int          taille;  // taille du buffer
  float        duree;   // dur�e du morceau en secondes

  vector<Lecture *> lectures; // listes des lectures
};

// *************************************** LECTURE

class Lecture {
  friend ostream & operator << (ostream &, const Lecture &);

 public:
    
  /* Type �num�r� indiquant le type de lecture :
     Persistante : la lecture reste dans les lectures de la source
     Volatile    : la source se charge de lib�rer la lecture � sa fin */
  enum Type {Persistante, Volatile};

  /* Type �num�r� indiquant le statut de la lecture */
  enum Statut {Stop, Play, Pause};

  /* Type �num�r� indiquant le moment de la vaporisation */
  enum Quand {Maintenant, A_la_fin};

  /* Cr�ation d'une lecture volatile, qui d�marre imm�diatement */
  static void creer_volatile(Source * _source);

  /* Cr�ation d'une lecture persistante, qui d�marre imm�diatement par d�faut */
  static Lecture * creer_persistante(Source * _source,
				     Statut   _statut = Play);

  /* Constructeur (PROTEGE !): 
     -> enregistre les param�tres de lecture
     -> enregistre la lecture dans la source */
 protected:
  Lecture(Type _type, Source * _source, Statut _statut);
 public:

  /* Destructeur */
  virtual ~Lecture();

  /* D�marrage de la lecture */
  virtual void lecture();

  /* Suspension de la lecture */
  virtual void pause();

  /* Arr�t de la lecture (suspension + r�initialisation de position) */
  virtual void stop();

  /* Transformation d'une lecture persistante en lecture volatile */
  virtual void vaporise(Quand quand = Maintenant);

  /* Mixage dans le buffer audio (appel� par le callback audio) */
  virtual void mix_audio(Uint8 *stream, int len);

  Source * source; // source � lire
  Type type;       // Type de lecture (persistante ou volatile)
  Statut statut;   // indicateur de l'�tat de lecture
  int i_buffer;    // indice de lecture dans le buffer de la source
};

// *************************************** LECTURERVVB

class LectureRVVB : public Lecture {
  friend ostream & operator << (ostream &, const LectureRVVB &);

 public:
    
  /* Cr�ation d'une lecture volatile, par d�faut :
     - qui d�marre imm�diatement
     - au volume normal
     - � la vitesse normale
     - � la balance centr�e */
  static void creer_volatile (Source * _source           ,
			      float    _volume  = 1      ,
			      float    _vitesse = 1      ,
			      float    _balance = 0.5    );

  /* Cr�ation d'une lecture persistante, par d�faut :
     - qui d�marre imm�diatement
     - au volume normal
     - � la vitesse normale
     - � la balance centr�e
     - qui ne sera jou�e qu'une fois */

  static LectureRVVB * creer_persistante (Source * _source             ,
					  float    _volume  = 1        ,
					  float    _vitesse = 1        ,
					  float    _balance = 0.5      ,
					  Statut   _statut  = Play     ,
					  bool     _repetition = false );

  /* Constructeur (PROTEGE !): 
     -> enregistre les param�tres de lecture
     -> enregistre la lecture dans la source */
 protected:
  LectureRVVB(Type _type, Source * _source, Statut _statut,
	      float _volume, float _vitesse, float _balance,
	      bool _repetition);
 public:
 
  /* Destructeur */
  virtual ~LectureRVVB();

  /* Arr�t de la lecture (suspension + r�initialisation de position) */
  virtual void stop();

  /* Transformation d'une lecture persistante en lecture volatile */
  virtual void vaporise(Quand quand);

  /* Mixage dans le buffer audio (appel� par le callback audio) */
  virtual void mix_audio(Uint8 *stream, int len);

  bool   repetition;   // indicateur de lecture simple ou en boucle
  float  volume;       // volume (ratio du volume normal)
  float  vitesse;      // vitesse de lecture (ratio de la vitesse normale)
  float  balance;      // balance (ratio du volume du canal de droite)
  int    taille_bloc;  // taille des blocs d'echantillons
  int    dernier_bloc; // indice du dernier bloc d'echantillon
  double position;     // indice de lecture des BLOCS D'ECHANTILLONS
};

#endif
